home *** CD-ROM | disk | FTP | other *** search
- #define ASYNCHRONOUS
- /* SCSIInquiry.c */
- /*
- * SCSIInquiry.c
- * Copyright © 1994 Apple Computer Inc. All rights reserved.
- * This is a minimal sample to illustrate the Asynchronous SCSI Manager.
- *
- * Note: this program will crash if the asynchronous SCSI Manager is
- * not installed. SCSI Simple Sample shows how to test for the presence
- * of the asynchronous SCSI Manager.
- */
- #include "SCSIInquiry.h"
-
- #ifndef THINK_C /* MPW includes */
- #include <Errors.h>
- #include <Script.h>
- #include <Types.h>
- #include <Files.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Events.h>
- #include <Windows.h>
- #include <ToolUtils.h>
- #include <Memory.h>
- #include <Menus.h>
- #include <Lists.h>
- #include <Printing.h>
- #include <Dialogs.h>
- #include <StandardFile.h>
- #include <Packages.h>
- #endif
-
- /*
- * Include the O.S. files in a specific order to make sure that we have
- * a definition for the _SCSIAtomic trap.
- */
- #include <Traps.h>
- #ifndef _SCSIAtomic
- #define _SCSIAtomic 0xA089
- #endif
- /*
- * As of this writing, the Asynchronous SCSI Manager definitions have
- * not been added to the standard header distribution. This include
- * references a working version that is stored in the application
- * folder hierarchy.
- */
- #include "SCSI.h"
-
- DeviceIdent gTargetDevice = { 0, 0, 0, 0 }; /* Target ID 0 */
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * SCSI Definitions
- */
- #define kScsiCmdInquiry 0x12 /* Device inquiry command */
-
- struct SCSI_6_Byte_Command { /* Six-byte command */
- unsigned char opcode; /* 0 */
- unsigned char lbn3; /* 1 lbn in low 5 */
- unsigned char lbn2; /* 2 */
- unsigned char lbn1; /* 3 */
- unsigned char len; /* 4 */
- unsigned char ctrl; /* 5 */
- };
- typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;
-
- struct SCSI_Inquiry_Data { /* Inquiry returns this */
- unsigned char devType; /* 0 Device type, */
- unsigned char devTypeMod; /* 1 Device type modifier */
- unsigned char version; /* 2 ISO/ECMA/ANSI version */
- unsigned char format; /* 3 Response data format */
- unsigned char length; /* 4 Additional Length */
- unsigned char reserved5; /* 5 Reserved */
- unsigned char reserved6; /* 6 Reserved */
- unsigned char flags; /* 7 Capability flags */
- unsigned char vendor[8]; /* 8-15 Vendor-specific */
- unsigned char product[16]; /* 16-31 Product id */
- unsigned char revision[4]; /* 32-35 Product revision */
- unsigned char vendorSpecific[20]; /* 36-55 Vendor stuff */
- unsigned char moreReserved[40]; /* 56-95 Reserved */
- };
- typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;
-
- SCSI_Inquiry_Data gInquiryData; /* Inquiry data goes here */
- unsigned long gInquirySize; /* Number of bytes read */
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * gSCSICommand is the command that we send to the device.
- */
- SCSI_6_Byte_Command gSCSICommand = {
- kScsiCmdInquiry, /* Command */
- 0, /* LBN 3 -- unused */
- 0, /* LBN 2 -- unused */
- 0, /* LBN 1 -- unused */
- sizeof (SCSI_Inquiry_Data), /* Returned buffer length */
- 0 /* Flags -- must be zero */
- };
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * The SCSIBusInquiry command returns the number of bytes in the parameter
- * block. We then allocate a block of the correct size. Note that the
- * block is cleared to zero when it is allocated.
- */
- SCSIBusInquiryPB gSCSIBusInquiryPB;
- SCSIExecIOPB *gSCSIExecIOPB;
- unsigned long gSCSIExecIOPBSize;
- Boolean gSCSICommandComplete;
- #define kCompletionTimeout (250) /* 250 Msec total time */
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Local functions and administrative variables.
- */
-
- #ifdef __powerc
- QDGlobals qd;
- #endif
-
- void DisplayError(
- OSErr errorStatus,
- ConstStr255Param errorMessage
- );
- OSErr DoSCSICommand(
- unsigned short targetID,
- const Ptr scsiCommand,
- SCSIInstr *requestTIB
- );
- void DisplaySCSIInquiry(
- long actualTransferCount
- );
- pascal void MySCSICallbackProc(
- void *ioPtr
- );
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Local functions and administrative variables.
- */
- void
- main(void)
- {
- short i;
- OSErr status;
- EventRecord eventRecord;
- long actualTransferCount;
-
- MaxApplZone();
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(0);
- for (i = 0; i < 3; i++)
- EventAvail(everyEvent, &eventRecord);
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Call the SCSIBusInquiry command to determine the length of the
- * command block for the actual transfer.
- */
- gSCSIBusInquiryPB.scsiPBLength = sizeof gSCSIBusInquiryPB;
- gSCSIBusInquiryPB.scsiFunctionCode = SCSIBusInquiry;
- gSCSIBusInquiryPB.scsiDevice = gTargetDevice;
- SCSIAction((SCSI_PB *) &gSCSIBusInquiryPB);
- status = gSCSIBusInquiryPB.scsiResult;
- if (status != noErr) {
- DisplayError(status, "\pSCSIBusInquiry failed");
- ExitToShell();
- }
- gSCSIExecIOPBSize = gSCSIBusInquiryPB.scsiIOpbSize;
- gSCSIExecIOPB = (SCSIExecIOPB *) NewPtrClear(gSCSIExecIOPBSize);
- if (gSCSIExecIOPB == NULL) {
- DisplayError(MemError(), "\pNo memory for param. block");
- ExitToShell();
- }
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Setup the parameter block for the user's request.
- */
- gSCSIExecIOPB->scsiPBLength = gSCSIExecIOPBSize;
- gSCSIExecIOPB->scsiFunctionCode = SCSIExecIO;
- gSCSIExecIOPB->scsiTimeout = kCompletionTimeout;
- gSCSIExecIOPB->scsiDevice = gTargetDevice;
- /*
- * Copy the command block into the SCSI ExecIO Parameter block to
- * centralize everything for debugging.
- */
- BlockMove(
- &gSCSICommand,
- &gSCSIExecIOPB->scsiCDB,
- sizeof gSCSICommand
- );
- gSCSIExecIOPB->scsiCDBLength = sizeof gSCSICommand;
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Specify the transfer direction, if any, and set the other SCSI
- * operation flags. scsiSIMQNoFreeze prevents the SCSI Manager from
- * blocking further operation if an error is detected.
- */
- gSCSIExecIOPB->scsiFlags =
- scsiSIMQNoFreeze /* Don't stop on errors */
- | scsiDirectionIn /* We're reading */
- | scsiDisableAutosense /* No Request Sense */
- | scsiDontDisconnect; /* No disconnect */
- gSCSIExecIOPB->scsiDataPtr = (unsigned char *) &gInquiryData;
- gSCSIExecIOPB->scsiDataLength = sizeof gInquiryData;
- gSCSIExecIOPB->scsiDataType = scsiDataBuffer;
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * For polled transfers, turn off select with attention so
- * the device doesn't disconnect. This is inefficient, but
- * is useful for the Device Identity, Mode Sense, and
- * some other administrative commands.
- */
- gSCSIExecIOPB->scsiHandshake[0] = 0; /* Not used for polled */
- gSCSIExecIOPB->scsiIOFlags |= scsiDisableSelectWAtn;
- gSCSIExecIOPB->scsiTransferType = scsiTransferPolled;
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Now, call the SCSI Command manager
- */
- #ifdef ASYNCHRONOUS
- gSCSIExecIOPB->scsiCompletion = MySCSICallbackProc;
- gSCSICommandComplete = false;
- #else
- gSCSIExecIOPB->scsiCompletion = NULL; /* Synchronous */
- #endif
- status = SCSIAction((SCSI_PB *) gSCSIExecIOPB);
- #ifdef ASYNCHRONOUS
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * In application that take advantage of the asynchronous SCSI
- * Manager, the mainline code would handle user interaction and
- * display management, while all SCSI and file I/O would be carried
- * out by I/O completion routines. This is a dummy event loop
- * that waits until the SCSIAction call completes by calling
- * MySCSICallbackProc. Note that we do not wait if the original
- * call to SCSIAction failed, presumably because of a bad
- * parameter.
- *
- * Note: if your application calls the SCSI Manager asynchronously
- * and SCSIAction returns noErr, your code MUST NOT examine any
- * field within the SCSI parameter block, or any memory that it
- * references until your completion routine has been called. Thus,
- * this sample DOES NOT examine gSCSIExecIOPB->scsiResult until
- * the global "completion flag" has been set.
- */
- if (status == noErr) {
- while (status == noErr && gSCSICommandComplete == false)
- EventAvail(everyEvent, &eventRecord);
- status = gSCSIExecIOPB->scsiResult;
- }
- #endif
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * If the device returned less data than we requested, the SCSI
- * Manager will return an error status. We check that we actually
- * received some data and cancel the error if this is the case.
- */
- actualTransferCount = gSCSIExecIOPB->scsiDataLength
- - gSCSIExecIOPB->scsiDataResidual;
- if (status == scsiDataRunError && actualTransferCount > 0)
- status = noErr;
- if (status != noErr)
- DisplayError(status, "\pSCSIAction");
- else {
- DisplaySCSIInquiry(actualTransferCount);
- }
- ExitToShell();
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * This completion routine is called by the SCSI Manager when the
- * SCSIAction procedure completes.
- */
- pascal void
- MySCSICallbackProc(
- void *ioPtr
- )
- {
- gSCSICommandComplete = true;
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Display the inquiry result.
- */
- static void
- StoreString(
- const unsigned char *textPtr,
- Size textLength,
- StringPtr result
- )
- {
- register short i;
-
- for (i = textLength; i > 0; --i) {
- if (textPtr[i - 1] != ' ' && textPtr[i - 1] != 0)
- break;
- }
- BlockMove(textPtr, &result[1], i);
- result[0] = i;
- }
-
- void
- DisplaySCSIInquiry(
- long actualTransferCount
- )
- {
- Str255 inquirySize;
- Str255 vendorName;
- Str255 productName;
- Str255 revisionLevel;
-
- NumToString(actualTransferCount, inquirySize);
- StoreString(
- gInquiryData.vendor,
- sizeof gInquiryData.vendor,
- vendorName
- );
- StoreString(
- gInquiryData.product,
- sizeof gInquiryData.product,
- productName
- );
- StoreString(
- gInquiryData.revision,
- sizeof gInquiryData.revision,
- revisionLevel
- );
- ParamText(inquirySize, vendorName, productName, revisionLevel);
- NoteAlert(ALRT_Info, NULL);
- }
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Display an error alert.
- */
- void
- DisplayError(
- OSErr errorStatus,
- ConstStr255Param errorMessage
- )
- {
- Str255 work;
-
- NumToString(errorStatus, work);
- ParamText(work, errorMessage, "\p", "\p");
- InitCursor();
- StopAlert(ALRT_Error, NULL);
- }
-
-